package com.sinodoggo.shitcloud.controller;


import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sinodoggo.shitcloud.commons.Constants;
import com.sinodoggo.shitcloud.commons.Result;
import com.sinodoggo.shitcloud.entity.Menu;
import com.sinodoggo.shitcloud.entity.Role;
import com.sinodoggo.shitcloud.entity.RoleMenu;
import com.sinodoggo.shitcloud.entity.User;
import com.sinodoggo.shitcloud.entity.dto.PasswordDTO;
import com.sinodoggo.shitcloud.entity.dto.UserDTO;
import com.sinodoggo.shitcloud.exception.ServiceException;
import com.sinodoggo.shitcloud.service.IMenuService;
import com.sinodoggo.shitcloud.service.IRoleMenuService;
import com.sinodoggo.shitcloud.service.IRoleService;
import com.sinodoggo.shitcloud.service.IUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  前端控制器
 * </p>
 *
 * @author sinodoggo
 * @since 2022-11-20
 */
@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private IUserService userService;
    @Resource
    private IRoleMenuService roleMenuService;
    @Resource
    private IRoleService roleService;
    @Resource
    private IMenuService menuService;

    /**
     * 获取用户对应菜单
     * @param roleIdentifier 角色的标志符
     * @return 结果集
     */
    private List<Menu> getUserMenu(String roleIdentifier) {
        // 查询角色对应的菜单ID
        QueryWrapper<Role> roleWrapper = new QueryWrapper<>();
        QueryWrapper<RoleMenu> roleMenuWrapper = new QueryWrapper<>();
        roleWrapper.eq("identifier", roleIdentifier);
        final Integer correspondingRoleId = roleService.getOne(roleWrapper).getId();
        roleMenuWrapper.eq("role_id", correspondingRoleId);
        final List<RoleMenu> roleMenus = roleMenuService.list(roleMenuWrapper);
        List<Integer> menuIds = roleMenus.stream().map(RoleMenu::getMenuId).collect(Collectors.toList());
        // 保存角色对应菜单的树形结构
        List<Menu> userMenu = new ArrayList<>();
        // 所有的父级菜单
        final List<Menu> allMenus = menuService.getAllMenus(null);
        for (Menu menu : allMenus) {
            if (menuIds.contains(menu.getId()) || null != menu.getChildren()) {
                // 如果父级存在子级或者含有父级则加入
                userMenu.add(menu);
            }
            // 获取该父级的子级菜单，重新遍历后更新到父级
            final List<Menu> subMenus = menu.getChildren();
            if (null != subMenus) {
                subMenus.removeIf(subMenu -> !menuIds.contains(subMenu.getId()));
                menu.setChildren(subMenus);
            }
        }
        return userMenu;
    }

    @GetMapping
    public Result getAllUsers() {
        final List<User> userList = userService.list();
        return Result.success(userList);
    }

    @GetMapping("/{id}")
    public Result getUserById(@PathVariable("id") Integer id) {
        final User user = userService.getById(id);
        return Result.success(user);
    }

    @PostMapping
    public Result saveOrUpdateUser(@RequestBody User user) {
        userService.saveOrUpdate(user);
        return Result.success();
    }

    @DeleteMapping("/{id}")
    public Result deleteUserById(@PathVariable("id") Integer id) {
        userService.removeById(id);
        return Result.success();
    }

    @PostMapping("/del/batch")
    public Result deleteBatchByIds(@RequestBody List<Integer> ids) {
        userService.removeBatchByIds(ids);
        return Result.success();
    }

    @GetMapping("/page")
    public Result pageDivision(@RequestParam("pageNumber") Integer pageNumber,
                               @RequestParam("pageSize") Integer pageSize,
                               @RequestParam(value = "userName", defaultValue = "") String userName,
                               @RequestParam(value = "nickName", defaultValue = "") String nickName,
                               @RequestParam(value = "phone", defaultValue = "") String phone) {
        final Page<User> page = new Page<>(pageNumber, pageSize);
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        if (!StrUtil.isBlank(userName)) {
            wrapper.like("user_name", userName);
        }
        if (!StrUtil.isBlank(nickName)) {
            wrapper.like("nick_name", nickName);
        }
        if (!StrUtil.isBlank(phone)) {
            wrapper.like("phone", phone);
        }
        wrapper.orderByDesc("id");
        return Result.success(userService.page(page, wrapper));
    }

    @GetMapping("/export")
    public Result exportUser(HttpServletResponse response) throws IOException {
        final List<User> userList = userService.list();
        ExcelWriter writer = ExcelUtil.getWriter(true);
        writer.write(userList, true);
        // 写出设置
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        String fileName = URLEncoder.encode("用户信息列表", "UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + fileName + ".xlsx");
        ServletOutputStream out = response.getOutputStream();
        writer.flush(out, true);
        out.close();
        writer.close();
        return Result.success();
    }

    @PostMapping("/import")
    public Result importUser(MultipartFile file) throws IOException {
        InputStream inputStream = file.getInputStream();
        ExcelReader reader = ExcelUtil.getReader(inputStream);
        final List<User> users = reader.readAll(User.class);
        userService.saveOrUpdateBatch(users);
        return Result.success();
    }

    @PostMapping("/login")
    public Result userLogin(@RequestBody UserDTO userDTO) {
        final String userName = userDTO.getUserName();
        final String password = userDTO.getPassword();
        if (StrUtil.isBlank(userName) || StrUtil.isBlank(password)) {
            throw new ServiceException(Constants.CODE_600, "用户名或密码不能为空");
        }
        UserDTO dto = userService.userLogin(userDTO);
        final String role = dto.getRole();
        final List<Menu> userMenu = this.getUserMenu(role);
        dto.setMenuList(userMenu);
        return Result.success(dto);
    }

    @PostMapping("/regist")
    public Result userRegist(@RequestBody UserDTO userDTO) {
        final String userName = userDTO.getUserName();
        final String password = userDTO.getPassword();
        if (StrUtil.isBlank(userName) || StrUtil.isBlank(password)) {
            throw new ServiceException(Constants.CODE_600, "用户名或密码不能为空!");
        }
        UserDTO dto = userService.userRegist(userDTO);
        return Result.success(dto);
    }

    @PostMapping("/retrive")
    public Result userRetrive(@RequestBody UserDTO userDTO) {
        final String userName = userDTO.getUserName();
        final String email = userDTO.getEmail();
        if (StrUtil.isBlank(userName) || StrUtil.isBlank(email)) {
            throw new ServiceException(Constants.CODE_600, "用户名或邮箱不能为空!");
        }
        UserDTO dto = userService.userRetrive(userDTO);
        return Result.success(dto);
    }

    /**
     * 重置密码接口
     * @param passwordDTO 密码传输对象
     * @return 结果集
     */
    @PostMapping("/reset-password")
    public Result resetPassword(@RequestBody PasswordDTO passwordDTO) {
        // 获取用户信息
        final Integer id = passwordDTO.getId();
        final String password = passwordDTO.getPassword();
        final String newPassword = passwordDTO.getNewPassword();
        QueryWrapper<User> wrapper = new QueryWrapper<>();
        wrapper.eq("id", id).eq("password", password);
        final User user = userService.getOne(wrapper);
        if (null != user) {
            user.setPassword(newPassword);
            userService.saveOrUpdate(user);
        } else {
            throw new ServiceException(Constants.CODE_600, "原密码输入错误!");
        }
        return Result.success();
    }
}

